/**
* Copyright (c) 2012-2013 Nokia Corporation. All rights reserved.
* Nokia and Nokia Connecting People are registered trademarks of Nokia Corporation. 
* Oracle and Java are trademarks or registered trademarks of Oracle and/or its
* affiliates. Other product and company names mentioned herein may be trademarks
* or trade names of their respective owners. 
* See LICENSE.TXT for license information.
*/
package com.nokia.example.explonoid.audio;

import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.Vector;
import javax.microedition.media.Manager;
import javax.microedition.media.MediaException;
import javax.microedition.media.Player;
import javax.microedition.media.PlayerListener;

/**
 * Handles the playback of audio samples.
 */
public class AudioManager extends Thread implements PlayerListener {

    private static boolean audioEnabled = true;
    private static final int MAX_PLAYERS = 4;
    private static AudioManager instance;
    private static final Vector playBuffer; // Play queue
    private boolean stopElectricity;
    private PlayItem[] players; // Currently playing items
    private int index;    

    static {
        playBuffer = new Vector();
        instance = new AudioManager();
        instance.start();
    }

    public static AudioManager getInstance() {
        if (instance == null) {
            instance = new AudioManager();
        }
        return instance;
    }

    public AudioManager() {
        players = new PlayItem[MAX_PLAYERS];
        index = 0;
        stopElectricity = false;
    }

    public void stopAll() {
        for (int i = 0; i < players.length; i++) {
            if (players[i] != null) {
                stop(players[i].getPlayer());
            }
        }
    }

    public void stopPlayer(String key) {
        // If the user presses the screen quickly, this event comes
        // before PlayItem is added to the players-list. This is why
        // there is a flag that informs this method has been called.
        stopElectricity = true;
        for (int i = 0; i < players.length; i++) {
            if (players[i] != null && players[i].filename.equals(key)) {
                stop(players[i].getPlayer());
            }
        }
    }

    public void stop(Player player) {
        if (player.getState() == Player.STARTED) {
            try {
                player.stop();
            } catch (Exception e) {
            }
        }
        player.close();
    }

    public void playerUpdate(Player player, String event, Object eventData) {
        if (event.equals(PlayerListener.END_OF_MEDIA)) {
            try {
                player.setMediaTime(0);
                player.start();
            } catch (MediaException me) {
                me.printStackTrace();
            }
        }
    }

    public void run() {
        while (true) {
            if (audioEnabled) {
                Enumeration e = null;
                PlayItem[] queue;
                synchronized (playBuffer) {
                    queue = new PlayItem[playBuffer.size()];
                    e = playBuffer.elements();
                    for (int i = 0; i < playBuffer.size(); i++) {
                        queue[i] = (PlayItem) e.nextElement();
                    }
                    playBuffer.removeAllElements();
                }
                for (int i = 0; i < queue.length; i++) {
                    PlayItem playItem = queue[i];
                    if (players[index] != null) {
                        stop(players[index].getPlayer());
                    }
                    players[index] = playItem;
                    index++;
                    if (index >= MAX_PLAYERS) {
                        index = 0;
                    }

                    try {
                        InputStream stream = AudioManager.class.getResourceAsStream(playItem.getFilename());
                        playItem.setPlayer(Manager.createPlayer(stream, "audio/mp3"));
                        playItem.getPlayer().start();
                        if (playItem.looped) {
                            playItem.getPlayer().addPlayerListener(this);
                            if (stopElectricity) {
                                playItem.getPlayer().stop();
                                stopElectricity = false;
                            }
                        }
                    } catch (IOException ex) {
                        ex.printStackTrace();
                    } catch (MediaException ex) {
                        ex.printStackTrace();
                    } catch (RuntimeException rex) {
                        rex.getMessage();
                        rex.printStackTrace();
                    }
                }
            }
            try {
                Thread.sleep(100);
            } catch (InterruptedException ex) {
                ex.printStackTrace();
            }
        }

    }

    public boolean loopSample(String filename) {
        stopElectricity = false;
        PlayItem playItem = new PlayItem(filename, true);
        synchronized (playBuffer) {
            if (playBuffer.size() < MAX_PLAYERS) {
                playBuffer.addElement(playItem);
            }
        }
        return true;
    }

    public void playSample(final String filename) {
        PlayItem playItem = new PlayItem(filename, false);
        synchronized (playBuffer) {
            playBuffer.addElement(playItem);
            while (playBuffer.size() >= MAX_PLAYERS) {
                playBuffer.removeElementAt(0);
            }
        }
    }
    
    public static void setAudioEnabled(boolean value) {
        synchronized (playBuffer) {
            playBuffer.removeAllElements();
        }
        audioEnabled = value;
    }

    private class PlayItem {

        public Player player;
        public String filename;
        public boolean looped;

        public PlayItem(String filename, boolean looped) {
            this.filename = filename;
            this.looped = looped;
        }

        public String getFilename() {
            return filename;
        }

        public Player getPlayer() {
            return player;
        }

        public void setPlayer(Player player) {
            this.player = player;
        }
    }
}
